#!/usr/bin/env python3
# -*- coding: utf-8 -*-

"""
EasyFTP - 主程序
v1.0版本
"""

import os
import sys
import json
import logging
import argparse
import subprocess
import time
import signal
from typing import Optional


class FtpTransferSystem:
    """双向FTP文件传输系统主类，管理服务器和客户端的角色切换"""

    def __init__(self, config_file='../config/config.json'):
        """初始化系统配置"""
        # 加载配置文件
        self.config = self._load_config(config_file)
        # 设置日志
        self._setup_logging()
        # 当前运行模式
        self.mode = None  # 'server' 或 'client'
        # 子进程
        self.process = None

    def _load_config(self, config_file):
        """加载配置文件"""
        try:
            with open(config_file, 'r', encoding='utf-8') as f:
                return json.load(f)
        except Exception as e:
            print(f"加载配置文件失败: {e}")
            # 返回默认配置
            return {
                "server": {
                    "host": "0.0.0.0",
                    "port": 2121,
                    "username": "user",
                    "password": "password",
                    "shared_dir": "./shared",
                    "passive_mode": True,
                    "passive_ports": {"start": 60000, "end": 65535}
                },
                "client": {
                    "default_host": "127.0.0.1",
                    "default_port": 2121
                },
                "logging": {
                    "level": "INFO",
                    "file": "ftp_transfer.log"
                }
            }

    def _setup_logging(self):
        """设置日志配置"""
        log_level = getattr(logging, self.config.get("logging", {}).get("level", "INFO").upper(), logging.INFO)
        log_file = self.config.get("logging", {}).get("file", "ftp_transfer.log")
        
        logging.basicConfig(
            level=log_level,
            format='%(asctime)s - %(name)s - %(levelname)s - %(message)s',
            handlers=[
                logging.FileHandler(log_file),
                logging.StreamHandler()
            ]
        )
        self.logger = logging.getLogger("FtpTransferSystem")

    def start_server(self, device_id=None):
        """启动FTP服务器"""
        self.mode = 'server'
        self.logger.info("正在启动FTP服务器...")
        
        # 获取Python解释器路径
        python = sys.executable
        # 服务器脚本路径
        server_script = os.path.join(os.path.dirname(__file__), 'ftp_server.py')
        
        # 构建命令行参数
        cmd_args = [python, server_script]
        # 如果提供了设备ID参数，则添加到命令行
        if device_id:
            cmd_args.extend(['--device-id', device_id])
            self.logger.info(f"将使用命令行指定的设备ID: {device_id}")
        
        try:
            # 启动服务器作为子进程，设置 bufsize=1 使输出行缓冲，确保实时显示设备验证码
            self.process = subprocess.Popen(
                cmd_args,
                stdout=subprocess.PIPE,
                stderr=subprocess.STDOUT,  # 将stderr合并到stdout
                text=True,
                bufsize=1
            )
            
            self.logger.info(f"FTP服务器已启动，进程ID: {self.process.pid}")
            self.logger.info(f"服务器监听端口: {self.config['server']['port']}")
            
            # 等待服务器启动并生成设备ID和验证码
            time.sleep(1)
            
            # 重新加载配置文件，读取设备ID和验证码
            try:
                with open('../config/config.json', 'r', encoding='utf-8') as f:
                    config_data = json.load(f)
                
                device_id = config_data['server'].get('device_id', 'linux01')
                device_code = config_data['server'].get('device_code', '未生成')
                
                # 直接显示设备ID和验证码给用户
                print("=" * 60)
                print(f"  设备ID: {device_id}")
                print(f"  设备验证码: {device_code}")
                print("=" * 60)
                print("请将上述信息提供给客户端用户进行连接验证")
            except Exception as e:
                self.logger.error(f"读取配置文件中的设备信息失败: {e}")
                print("警告: 无法直接获取设备验证码，请查看服务器启动日志")
            
            # 打印服务器输出，同时读取stdout和stderr
            while self.process.poll() is None:
                if self.process.stdout:
                    # 使用非阻塞方式读取，避免卡住
                    import select
                    ready_to_read, _, _ = select.select([self.process.stdout], [], [], 0.1)
                    if ready_to_read:
                        line = self.process.stdout.readline()
                        if line:
                            print(line.strip())
                            self.logger.info(f"服务器输出: {line.strip()}")
                time.sleep(0.1)
                
            # 检查进程退出状态
            if self.process.returncode != 0:
                self.logger.error(f"服务器异常退出，返回代码: {self.process.returncode}")
                if self.process.stderr:
                    error_output = self.process.stderr.read()
                    self.logger.error(f"服务器错误输出: {error_output}")
        except Exception as e:
            self.logger.error(f"启动服务器失败: {e}")
        finally:
            self.process = None

    def start_client(self, host=None, port=None, device_id=None, device_code=None, command=None, *args):
        """启动FTP客户端"""
        self.mode = 'client'
        self.logger.info("正在启动FTP客户端...")
        
        # 获取Python解释器路径
        python = sys.executable
        # 客户端脚本路径
        client_script = os.path.join(os.path.dirname(__file__), 'ftp_client.py')
        
        # 构建命令行参数
        cmd_args = [python, client_script]
        
        # 添加连接参数
        if host:
            cmd_args.extend(['--host', host])
        if port:
            cmd_args.extend(['--port', str(port)])
        if device_id:
            cmd_args.extend(['--device-id', device_id])
        if device_code:
            cmd_args.extend(['--device-code', device_code])
        
        # 添加客户端命令和参数
        if command:
            cmd_args.append(command)
            cmd_args.extend(args)
        
        try:
            # 启动客户端作为子进程
            result = subprocess.run(
                cmd_args,
                stdout=subprocess.PIPE,
                stderr=subprocess.PIPE,
                text=True
            )
            
            # 打印输出
            if result.stdout:
                print(result.stdout)
                self.logger.info(f"客户端输出: {result.stdout}")
            
            # 打印错误
            if result.returncode != 0 and result.stderr:
                print(result.stderr, file=sys.stderr)
                self.logger.error(f"客户端错误输出: {result.stderr}")
            elif result.stderr:
                # 如果命令执行成功但有stderr输出，这些可能只是日志信息
                print(result.stderr)
                self.logger.info(f"客户端日志输出: {result.stderr}")
            
            if result.returncode != 0:
                self.logger.error(f"客户端执行失败，返回代码: {result.returncode}")
            else:
                self.logger.info("客户端执行成功")
                
        except Exception as e:
            self.logger.error(f"启动客户端失败: {e}")

    def stop(self):
        """停止当前运行的服务"""
        if self.process:
            try:
                self.logger.info(f"正在停止{self.mode}...")
                # 发送终止信号
                if os.name == 'nt':  # Windows
                    self.process.kill()
                else:  # Unix-like
                    os.kill(self.process.pid, signal.SIGTERM)
                    # 等待进程结束
                    self.process.wait(timeout=5)
                self.logger.info(f"{self.mode}已停止")
            except Exception as e:
                self.logger.error(f"停止{self.mode}失败: {e}")
            finally:
                self.process = None
        
        self.mode = None

    def print_status(self):
        """打印当前系统状态"""
        print("=== 双向FTP文件传输系统状态 ===")
        if self.mode:
            print(f"当前模式: {self.mode}")
            if self.mode == 'server':
                print(f"服务器配置:")
                print(f"  监听地址: {self.config['server']['host']}:{self.config['server']['port']}")
                print(f"  设备ID: {self.config['server'].get('device_id', 'linux01')}")
                print(f"  共享目录: {self.config['server']['shared_dir']}")
                # 提醒用户查看设备验证码
                print("  设备验证码: 请查看服务器启动时的输出")
            else:
                print(f"客户端配置:")
                print(f"  默认服务器: {self.config['client']['default_host']}:{self.config['client']['default_port']}")
        else:
            print("系统未运行")
        print("=========================")


def main():
    """主函数"""
    # 解析命令行参数
    parser = argparse.ArgumentParser(description='双向FTP文件传输系统')
    parser.add_argument('-c', '--config', default='../config/config.json', help='配置文件路径')
    
    # 子命令
    subparsers = parser.add_subparsers(dest='command', help='命令')
    
    # server命令
    server_parser = subparsers.add_parser('server', help='启动FTP服务器')
    server_parser.add_argument('-d', '--device-id', help='指定设备ID')
    
    # client命令
    client_parser = subparsers.add_parser('client', help='启动FTP客户端')
    client_parser.add_argument('-H', '--host', help='服务器IP地址')
    client_parser.add_argument('-P', '--port', type=int, help='服务器端口')
    client_parser.add_argument('-d', '--device-id', help='设备ID')
    client_parser.add_argument('-k', '--device-code', help='设备验证码')
    client_parser.add_argument('client_command', nargs='?', help='客户端命令(list/upload/download/mkdir/rmdir)')
    client_parser.add_argument('client_args', nargs='*', help='客户端命令参数')
    
    # status命令
    subparsers.add_parser('status', help='显示系统状态')
    
    args = parser.parse_args()
    
    # 创建系统实例
    ftp_system = FtpTransferSystem(args.config)
    
    try:
        # 处理命令
        if args.command == 'server':
            ftp_system.start_server(args.device_id)
        elif args.command == 'client':
            ftp_system.start_client(
                args.host,
                args.port,
                args.device_id,
                args.device_code,
                args.client_command,
                *args.client_args
            )
        elif args.command == 'status':
            ftp_system.print_status()
        else:
            parser.print_help()
    except KeyboardInterrupt:
        print("\n接收到中断信号，正在停止系统...")
    finally:
        ftp_system.stop()


if __name__ == '__main__':
    main()